"""A game runner.  Runs games until it's killed with Control-C."""

__author__ = "Gabriel Taubman (gtaubman@mac.com)"

import models
import os
import profile
import sys
import types
import time

from constants import DATABASE_FILE
from dbutils import *
from game import Game, GameOutcome
from player import Player
from word_list import WordList

Session = models.SessionMaker(DATABASE_FILE)

def ValidatePlayers():
  """Goes through the database validating unvalidated players.
  
  It checks to see if their file_data contains a subclass of Player.  If so
  they're validated.  If not they have their status set to an error.
  """
  session = Session()
  players = PlayersToValidate(session)

  print "There are %d players to validate." % len(players)

  # First, go through and write all the files to disk.
  for player in players:
    player.WriteFileToDisk()

  # Next, go through each player, import their module, and check for a subclass
  # of Player.  If we find one, mark them validated.
  for player in players:
    module_obj = __import__("%s" % (player.DiskFileName()))
    player_classes = []
    for item in dir(module_obj):
      obj = module_obj.__dict__[item]
      if (item != "Player" and
          isinstance(obj, types.ClassType) and
          issubclass(obj, Player)):
        player_classes.append(obj)

    num_players = len(player_classes)
    if num_players != 1:
      # We support one and only one player.  If there is another number, mark
      # this player is invalid for that reason.
      error = ("Invalid: Found %d player instances.  Exactly 1 required." %
               num_players)
      player.status = -1;
      player.status_message = error
      player.enabled = False
    else:
      # Mark this player is verified.
      player.status = 1
      player.status_message = "Validated"
      player.player_class_name = player_classes[0].__name__
  session.commit()

  # Clean up after ourselves.
  for player in players:
    player.RemoveFileFromDisk()


if __name__ == "__main__":
  session = Session()

  print "Loading Wordlist."
  wl = WordList()
  try:
    while True:
      print "Validating Players"
      ValidatePlayers()

      print "Getting a list of valid players."
      players = ValidPlayers(session)
      if len(players) < 2:
        # If there aren't enough players, don't go insane looking for them.
        time.sleep(60)
        continue

      for player1 in players:
        for player2 in players:
          if player1 == player2:
            continue

          # We have our two players chosen.  Write their files to disk.
          player1.WriteFileToDisk()
          player2.WriteFileToDisk()

          # Import both of their players.
          player1cmd = "from %s import %s as Player1Code" % (
              player1.DiskFileName(),
              player1.player_class_name)
          
          player2cmd = "from %s import %s as Player2Code" % (
              player2.DiskFileName(),
              player2.player_class_name)

          exec(player1cmd)
          exec(player2cmd)

          first_player = Player1Code()
          second_player = Player2Code()

          g = Game(wl)
          g.AddPlayer(first_player)
          g.AddPlayer(second_player)

          game_start = time.time()
          results = g.RunGame()
          game_end = time.time()

          # Now that the game is over erase our files.
          player1.RemoveFileFromDisk()
          player2.RemoveFileFromDisk()

          if results.reason != GameOutcome.CLEAN_GAME:
            # Bum game.  Skip it.
            # TODO(gtaubman): Figure out how cheated and record it.
            continue

          # Update the win tallies.
          if results.scores[first_player] > results.scores[second_player]:
            player1.games_won += 1
            player2.games_lost += 1
          elif results.scores[first_player] < results.scores[second_player]:
            player1.games_lost += 1
            player2.games_won += 1
          else:
            player1.games_tied += 1
            player2.games_tied += 1

          # Add an entry for this game.
          game_entry = models.Game()
          game_entry.match_length = game_end - game_start
          session.add(game_entry)

          # Add the scores for this game.
          p1_score = models.Score()
          p1_score.player = player1
          p1_score.game = game_entry
          p1_score.score = results.scores[first_player]

          p2_score = models.Score()
          p2_score.player = player2
          p2_score.game = game_entry
          p2_score.score = results.scores[second_player]

          session.add(p1_score)
          session.add(p2_score)

          session.commit()

  except KeyboardInterrupt:
    print "Shutting down."
